package com.luke.nio.group_chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 群聊服务端
 * @Descrtption GroupChatServer
 * @Author luke
 * @Date 2020/4/27
 **/
public class GroupChatServer {

    private static final int PORT = 8765;

    private ServerSocketChannel serverSocketChannel;

    public static void main(String[] args) {
        new GroupChatServer();
    }

    public  GroupChatServer(){
        try {
            //创建ServerSocketChannel
            serverSocketChannel = ServerSocketChannel.open();
            //创建Selector
            Selector selector = Selector.open();

            //ServerSocketChannel监听端口
            serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
            serverSocketChannel.configureBlocking(false);

            //将ServerSocketChannel注册到Selector上，监听连接事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //Selector开始扫描各个通道是否有事件发生
            while (true){
                int selectCount = selector.select(2000);
                if(selectCount > 0){
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();//获取到事件发生的SelectionKey集合
                    Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
                    while (selectionKeyIterator.hasNext()){//遍历所有的SelectionKey
                        SelectionKey selectionKey = selectionKeyIterator.next();

                        //获取SelectionKey发生的事件
                        if(selectionKey.isAcceptable()){//OP_ACCEPT事件发生，表明有客户端连接进来
                            //获取到连接的客户端
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            socketChannel.configureBlocking(false);
                            //注册到选择器上
                            socketChannel.register(selector,SelectionKey.OP_READ);//监听读事件
                            System.out.println(socketChannel.getRemoteAddress()+" 连接上来");
                        }

                        if(selectionKey.isReadable()){//OP_READ事件发生，表示接收到客户端消息
                            //通过SelectionKey拿到对应的Channel，实际上是SocketChannel
                            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                            //分配对应的缓冲区
                            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                            //获取客户端消息，写入到缓冲区中
                            socketChannel.read(byteBuffer);
                            //将消息答应出来
                            String message = new String(byteBuffer.array());
                            System.out.println("接收到客户端【"+socketChannel.getRemoteAddress()+"】消息："+message);

                            //将消息转发到其他的客户端
                            msgDispatchToOtherClient(message,selector,socketChannel);
                        }

                        selectionKeyIterator.remove();//避免重复遍历
                    }
                }else{
                    //System.out.println("等待客户端连接。。。");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 消息转发给其他客户端
     * @param msg
     * @param excludeSocketChannel
     */
    private void msgDispatchToOtherClient(String msg,Selector selector,SocketChannel excludeSocketChannel) throws IOException{
        System.out.println("消息转发");
        //获取到所有的SelectionKey
        Set<SelectionKey> selectionKeys = selector.keys();
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()){
            SelectionKey selectionKey = iterator.next();
            SelectableChannel channel = selectionKey.channel();//包含了SocketChannel和ServerSocketChannel
            //将消息转发给其他客户端
            if(channel instanceof SocketChannel && channel != excludeSocketChannel){
                ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
                ((SocketChannel) channel).write(byteBuffer);
            }
        }

    }

}
